﻿using SvGame.Objects;
using System.Numerics;
using UtilLib;

namespace SvGame.Logic;

// 攻击类型
public enum EAttackType
{
    Regular = 0, // 常规
    Quick = 1, // 快攻
    Riposte = 2, // 反击
    Perform = 3, // 特殊攻击
}
// 攻击结果
public enum EAttackResult
{
    None = 0,
    Dodge = 1,
    Parry = 2,
    Damage = 3,
}

public static partial class GameLogic
{
    /// <summary>
    /// 尝试攻击
    /// </summary>
    /// <param name="me"></param>
    /// <param name="victim"></param>
    public static void TryAttack(this IRole me, IRole victim)
    {
        // 不存活 死亡或者昏迷
        if (!me.Living)
        {
            me.Comb.Guarding = false;
            return;
        }
        if (victim.IsBusy || !victim.Living) 
        {
            me.Comb.Guarding = false;
            if (!victim.FightHas(me.Uid))
            {
                victim.FightOb(me);
            }
            me.DoAttack(victim, me.Comb.Weapon, EAttackType.Quick);
            return;
        }
        // me精神+胆识 > 随机数(ob精神*2)
        // 发动一次普通攻击
        if (me.StatusCur.Sen + me.Talent.Cor > Rd(victim.StatusCur.Sen * 2))
        {
            me.Comb.Guarding = false;
            victim.FightOb(me);
            me.DoAttack(victim, me.Comb.Weapon, EAttackType.Regular);
            return;
        }
        if (!me.Comb.Guarding)
        {
            me.Comb.Guarding = true;
            MessageVision(ConfDescGuardExt.RandomSingle(), me, victim);
            return;
        }
    }
    /// <summary>
    /// 攻击
    /// </summary>
    /// <param name="me"></param>
    /// <param name="ob"></param>
    /// <param name="weaponUse"></param>
    /// <param name="attackType"></param>
    public static void DoAttack(this IRole me, 
        IRole victim, 
        Equip? weaponUse, 
        EAttackType attackType = EAttackType.Regular)
    {
        var attackResult = EAttackResult.None;
        //loger.Debug($"DoAttack");
        // 双方位于非战斗场景，停止战斗
        var room = me.Room;
        if (!room.CanFight()) 
        {
            MessageVision("$N和$n各自退了一步，收住了招。", me, victim);
            me.FightRemove(victim);
            victim.FightRemove(me);
            return;
        }
        // 双方不在同一场景，停止战斗
        if (!room.Same(victim.Room))
        {
            me.FightRemove(victim);
            victim.FightRemove(me);
            return;
        }
        var weapon = weaponUse;
        if (weapon == null)
        {
            weapon = me.Comb.Weapon;
        }
        var act = me.ActionGet();
        var sbAttackMessage = new StringBuilder();
        sbAttackMessage.AppendLine($"{act.Desc}！");
        var ap = me.GetAttackPower(out var attackSkillId);
        ap = Math.Max(ap, 1);

        var dp = victim.GetDodgePower(out var dodgeSkillId);
        dp = Math.Max(dp, 1);

        int dp修正值 = 0;
        var dp描述 = "";

        long pp = 0;

        long damage = 0, damageKee = 0, damageBonus = 0;
        bool wounded = false;

        // 目标的轻功修正值
        if (ConfSkillDodgeExt.TryGetValues(dodgeSkillId, out var dodgeIdList))
        {
            if (dodgeIdList.Count > 0)
            {
                var dodgeId = dodgeIdList.RandomSingle();
                var confDodge = ConfSkillDodge[dodgeId];
                dp修正值 += confDodge.DodgePower;
                dp描述 = confDodge.Desc;
            }
        }
        // 攻击者aciton里的轻功减少
        if (act.Dodge != 0)
        {
            dp修正值 += act.Dodge;
        }
        // 防御者的闪避修正值
        dp修正值 += victim.GetProp(EProp.dodge);
        if (dp修正值 != 0)
        {
            dp = dp * (100 + dp修正值) / 100;
        }

        // 判断闪避
        if (Rd(ap + dp) < dp)
        {
            // todo DoAttack 是否增加轻功的经验值
            if (dp描述.IsNullOrEmpty())
            {
                dp描述 = ConfDescDodge.Values.RandomSingle().Desc;
            }
            attackResult = EAttackResult.Dodge;
            sbAttackMessage.Append(dp描述);
        }
        else
        {
            // 判断招架
            pp = victim.GetParryPower(out var parrySkillId);
            pp = Math.Max(pp, 1);
            int pp修正值 = 0;
            if (act.Parry != 0)
            {
                pp修正值 += act.Parry;
            }
            // 防御者的招架修正值
            dp修正值 += victim.GetProp(EProp.parry);
            if (pp修正值 != 0)
            {
                pp = pp * (100 + pp修正值) / 100;
            }
            if (Rd(ap + pp) < pp)
            {
                attackResult = EAttackResult.Parry;
                var pp描述 = victim.Comb.ActParryMsgs.RandomSingle();
                sbAttackMessage.Append(pp描述);
            }
            else
            {
                // 命中
                attackResult = EAttackResult.Damage;

                // 基础伤害
                damageKee = me.GetProp(EProp.damage) + act.Damage;

                // 随机
                damageKee = (damageKee + Rd(damageKee)) / 2;

                // 招式系数
                if (act.DamageRatio > 0)
                {
                    damageKee = damageKee * act.DamageRatio / 100;
                }

                // 高级伤害
                damageBonus = me.Talent.Str + act.Bonus / 2;

                // todo DoAttack 内力加力

                // 随机
                damageBonus = (damageBonus + Rd(damageBonus)) / 2;

                // 招式系数
                if (act.BonusRatio > 0)
                {
                    damageBonus = damageBonus * act.BonusRatio / 100;
                }

                // 总伤害
                damage = damageKee + damageBonus;


                // 如果双方经验差距过大 伤害折损
                var defenseFactor = victim.Exp;
                while (Rd(defenseFactor) > me.Exp)
                {
                    damage = damage * 2 / 3;
                    defenseFactor /= 2;
                }

                // 伤害
                victim.ReceiveDamageKee((int)damage, me);

                // 伤害上限 计算护甲
                if (me.KillHas(victim.Uid) || weapon != null)
                {
                    var armor = victim.GetProp(EProp.armor);
                    if (Rd(damage) > armor)
                    {
                        victim.ReceiveWoundKee((int)(damage - armor), me);
                        wounded = true;
                    }
                }

                // 伤害描述
                sbAttackMessage.Append(DamageMessage((int)damage, act.DamageType));
            }
        }

        var debugmsg = $"me:{me.Name} ap:{ap} dp:{dp} pp:{pp} attackResult:{attackResult}";
        debugmsg += $"act:{act.Id} damageKee:{damageKee} damageBonus:{damageBonus} damage:{damage}";
        loger.Debug(debugmsg);

        //me.Message(debugmsg);
        //victim.Message(debugmsg);

        // 部位描述
        var limb = me.GetLimb();
        var attackMessage = sbAttackMessage.ToString();
        attackMessage = attackMessage.Replace("$l", limb);

        // 武器描述
        if (weapon != null)
        {
            attackMessage = attackMessage.Replace("$w", weapon.Cfg.Name);
        }
        if (victim.Comb.Weapon != null)
        {
            attackMessage = attackMessage.Replace("$W", victim.Comb.Weapon.Cfg.Name);
        }

        MessageVision(attackMessage, me, victim);

        // 刷新HP
        me.Hp();
        victim.Hp();

        if (damage > 0)
        {
            ReportStatusKee(victim, wounded);

            // 比试中断判断
            if (!me.KillHas(victim.Uid) && !victim.KillHas(me.Uid))
            {
                if (victim.StatusCur.Kee < victim.StatusMax.Kee / 2)
                {
                    me.FightRemove(victim);
                    victim.FightRemove(me);
                    MessageVision(ConfDescWinnerExt.RandomSingle(), me, victim);
                }
            }
        }

        // todo DoAttack 连击判断

        // 反击判断 普通攻击 未造成伤害 防御姿态
        if (attackType == EAttackType.Regular
            && damage < 1
            && victim.Comb.Guarding)
        {
            victim.Comb.Guarding = false;
            if (Rd(victim.Talent.Cps) < 5)
            {
                MessageVision("$N一击不中，露出了破绽！", me);
                victim.DoAttack(me, victim.Comb.Weapon, EAttackType.Quick);
            }
            else
            {
                MessageVision("$N见$n攻击失误，趁机发动攻击！", victim, me);
                victim.DoAttack(me, victim.Comb.Weapon, EAttackType.Riposte);
            }
        }

    }
}
